home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / src / unexnext.c < prev    next >
C/C++ Source or Header  |  1993-07-23  |  9KB  |  431 lines

  1. /* Dump Emacs in macho format.
  2.    Copyright (C) 1990, 1993 Free Software Foundation, Inc.
  3.    Written by Bradley Taylor (btaylor@next.com).
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. #undef __STRICT_BSD__
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27. #include <mach/mach.h>
  28. #include <mach-o/loader.h>
  29. #include <sys/file.h>
  30. #include <sys/stat.h>
  31. #include <libc.h>
  32.  
  33.  
  34. int malloc_cookie;
  35.  
  36. /*
  37.  * Kludge: we don't expect any program data beyond VM_HIGHDATA
  38.  * What is really needed is a way to find out from malloc() which
  39.  * pages it vm_allocated and write only those out into the data segment.
  40.  *
  41.  * This kludge may break when we stop using fixed virtual address
  42.  * shared libraries. Actually, emacs will probably continue working, but be 
  43.  * much larger on disk than it needs to be (because non-malloced data will
  44.  * be in the file).
  45.  */
  46. static const unsigned VM_HIGHDATA = 0x2000000;
  47.  
  48. typedef struct region_t {
  49.     vm_address_t address;
  50.     vm_size_t size;
  51.     vm_prot_t protection;
  52.     vm_prot_t max_protection;
  53.     vm_inherit_t inheritance;
  54.     boolean_t shared;
  55.     port_t object_name;
  56.     vm_offset_t offset;
  57. } region_t;
  58.  
  59.  
  60. static void
  61. grow(
  62.      struct load_command ***the_commands,
  63.      unsigned *the_commands_len
  64.      )
  65. {
  66.     if (*the_commands == NULL) {
  67.         *the_commands_len = 1;
  68.         *the_commands = malloc(sizeof(*the_commands));
  69.     } else {
  70.         (*the_commands_len)++;
  71.         *the_commands = realloc(*the_commands, 
  72.                     (*the_commands_len *
  73.                      sizeof(**the_commands)));
  74.     }
  75. }
  76.  
  77.  
  78. static void
  79. save_command(
  80.          struct load_command *command,
  81.          struct load_command ***the_commands,
  82.          unsigned *the_commands_len
  83.          )
  84. {
  85.     struct load_command **tmp;
  86.  
  87.     grow(the_commands, the_commands_len);
  88.     tmp = &(*the_commands)[*the_commands_len - 1];
  89.     *tmp = malloc(command->cmdsize);
  90.     bcopy(command, *tmp, command->cmdsize);
  91. }
  92.  
  93. static void
  94. fatal_unexec(char *format, ...)
  95. {
  96.     va_list ap;
  97.  
  98.     va_start(ap, format);
  99.     fprintf(stderr, "unexec: ");
  100.     vfprintf(stderr, format, ap);
  101.     fprintf(stderr, "\n");
  102.     va_end(ap);
  103. }
  104.  
  105. static int
  106. read_macho(
  107.        int fd,
  108.        struct mach_header *the_header,
  109.        struct load_command ***the_commands,
  110.        unsigned *the_commands_len
  111.        )
  112. {
  113.     struct load_command command;
  114.     struct load_command *buf;
  115.     int i;
  116.     int size;
  117.  
  118.     if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
  119.         fatal_unexec("cannot read macho header");
  120.         return (0);
  121.     }
  122.     for (i = 0; i < the_header->ncmds; i++) {
  123.         if (read(fd, &command, sizeof(struct load_command)) != 
  124.             sizeof(struct load_command)) {
  125.               fatal_unexec("cannot read macho load command header");
  126.             return (0);
  127.         }
  128.         size = command.cmdsize - sizeof(struct load_command);
  129.         if (size < 0) {
  130.               fatal_unexec("bogus load command size");
  131.             return (0);
  132.         }
  133.         buf = malloc(command.cmdsize);
  134.         buf->cmd = command.cmd;
  135.         buf->cmdsize = command.cmdsize;
  136.         if (read(fd, ((char *)buf + 
  137.                   sizeof(struct load_command)), 
  138.              size) != size) {
  139.               fatal_unexec("cannot read load command data");
  140.             return (0);
  141.         }
  142.         save_command(buf, the_commands, the_commands_len);
  143.     }
  144.     return (1);
  145. }
  146.  
  147. static int
  148. filldatagap(
  149.         vm_address_t start_address,
  150.         vm_size_t *size,
  151.         vm_address_t end_address
  152.         )
  153. {
  154.     vm_address_t address;
  155.     vm_size_t gapsize;
  156.  
  157.     address = (start_address + *size);
  158.     gapsize = end_address - address;
  159.     *size += gapsize;
  160.     if (vm_allocate(task_self(), &address, gapsize,
  161.             FALSE) != KERN_SUCCESS) {
  162.         fatal_unexec("cannot vm_allocate");
  163.             return (0);
  164.     }
  165.     return (1);
  166. }
  167.  
  168. static int
  169. get_data_region(
  170.         vm_address_t *address,
  171.         vm_size_t *size
  172.         )
  173. {
  174.     region_t region;
  175.     kern_return_t ret;
  176.     struct section *sect;
  177.  
  178.     sect = getsectbyname(SEG_DATA, SECT_DATA);
  179.     region.address = 0;
  180.     *address = 0;
  181.     for (;;) {
  182.         ret = vm_region(task_self(), 
  183.                 ®ion.address, 
  184.                 ®ion.size, 
  185.                 ®ion.protection, 
  186.                 ®ion.max_protection, 
  187.                 ®ion.inheritance,
  188.                 ®ion.shared, 
  189.                 ®ion.object_name, 
  190.                 ®ion.offset);
  191.         if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
  192.             break;
  193.         }
  194.         if (*address != 0) {
  195.             if (region.address > *address + *size) {
  196.                 if (!filldatagap(*address, size, 
  197.                          region.address)) {
  198.                     return (0);
  199.                 }
  200.             } 
  201.             *size += region.size;
  202.         } else {
  203.             if (region.address == sect->addr) {
  204.                 *address = region.address;
  205.                 *size = region.size;
  206.             } 
  207.         }
  208.         region.address += region.size;
  209.     }
  210.     return (1);
  211. }
  212.  
  213. static char *
  214. my_malloc(
  215.       vm_size_t size
  216.       )
  217. {
  218.     vm_address_t address;
  219.  
  220.     if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
  221.         return (NULL);
  222.     }
  223.     return ((char *)address);
  224. }
  225.  
  226. static void
  227. my_free(
  228.     char *buf,
  229.     vm_size_t size
  230.     )
  231. {
  232.     vm_deallocate(task_self(), (vm_address_t)buf, size);
  233. }
  234.  
  235. static int
  236. unexec_doit(
  237.         int infd,
  238.         int outfd
  239.         )
  240. {
  241.     int i;
  242.     struct load_command **the_commands = NULL;
  243.     unsigned the_commands_len;
  244.     struct mach_header the_header;
  245.     int fgrowth;
  246.     int fdatastart;
  247.     int fdatasize;
  248.     int size;
  249.     struct stat st;
  250.     char *buf;
  251.     vm_address_t data_address;
  252.     vm_size_t data_size;
  253.  
  254.     struct segment_command *segment;
  255.  
  256.     if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
  257.         return (0);
  258.     }
  259.  
  260.  
  261.     malloc_cookie = malloc_freezedry ();
  262.     if (!get_data_region(&data_address, &data_size)) {
  263.         return (0);
  264.     }
  265.  
  266.  
  267.     /*
  268.      * DO NOT USE MALLOC IN THIS SECTION
  269.      */
  270.     {
  271.         /*
  272.          * Fix offsets
  273.          */
  274.         for (i = 0; i < the_commands_len; i++) {
  275.             switch (the_commands[i]->cmd) {
  276.             case LC_SEGMENT:
  277.                 segment = ((struct segment_command *)
  278.                        the_commands[i]);
  279.                 if (strcmp(segment->segname, SEG_DATA) == 0) {
  280.                     fdatastart = segment->fileoff;
  281.                     fdatasize = segment->filesize;
  282.                     fgrowth = (data_size - 
  283.                            segment->filesize);
  284.                     segment->vmsize = data_size;
  285.                     segment->filesize = data_size;
  286.                 }
  287.                 break;
  288.             case LC_SYMTAB:
  289.                 ((struct symtab_command *)
  290.                  the_commands[i])->symoff += fgrowth;
  291.                 ((struct symtab_command *)
  292.                  the_commands[i])->stroff += fgrowth;
  293.                 break;
  294.             case LC_SYMSEG:
  295.                 ((struct symseg_command *)
  296.                  the_commands[i])->offset += fgrowth;
  297.                 break;
  298.             default:
  299.                 break;
  300.             }
  301.         }
  302.         
  303.         /*
  304.          * Write header
  305.          */
  306.         if (write(outfd, &the_header, 
  307.               sizeof(the_header)) != sizeof(the_header)) {
  308.             fatal_unexec("cannot write output file");
  309.             return (0);
  310.         }
  311.         
  312.         /*
  313.          * Write commands
  314.          */
  315.         for (i = 0; i < the_commands_len; i++) {
  316.             if (write(outfd, the_commands[i], 
  317.                   the_commands[i]->cmdsize) != 
  318.                 the_commands[i]->cmdsize) {
  319.                   fatal_unexec("cannot write output file");
  320.                 return (0);
  321.             }
  322.         }
  323.         
  324.         /*
  325.          * Write original text
  326.          */
  327.         if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
  328.               L_SET) < 0) {
  329.               fatal_unexec("cannot seek input file");
  330.             return (0);
  331.         }
  332.         size = fdatastart - (sizeof(the_header) + 
  333.                      the_header.sizeofcmds);
  334.         buf = my_malloc(size);
  335.         if (read(infd, buf, size) != size) {
  336.             my_free(buf, size);
  337.               fatal_unexec("cannot read input file");
  338.         }
  339.         if (write(outfd, buf, size) != size) {
  340.             my_free(buf, size);
  341.             fatal_unexec("cannot write output file");
  342.             return (0);
  343.         }
  344.         my_free(buf, size);
  345.         
  346.         
  347.         /*
  348.          * Write new data
  349.          */
  350.         if (write(outfd, (char *)data_address, 
  351.               data_size) != data_size) {
  352.             fatal_unexec("cannot write output file");
  353.             return (0);
  354.         }
  355.         
  356.     }
  357.  
  358.     /*
  359.      * OKAY TO USE MALLOC NOW
  360.      */
  361.  
  362.     /*
  363.      * Write rest of file
  364.      */
  365.     fstat(infd, &st);
  366.     if (lseek(infd, fdatasize, L_INCR) < 0) {
  367.         fatal_unexec("cannot seek input file");
  368.         return (0);
  369.     }
  370.     size = st.st_size - lseek(infd, 0, L_INCR);
  371.  
  372.     buf = malloc(size);
  373.     if (read(infd, buf, size) != size) {
  374.         free(buf);
  375.         fatal_unexec("cannot read input file");
  376.         return (0);
  377.     }
  378.     if (write(outfd, buf, size) != size) {
  379.         free(buf);
  380.         fatal_unexec("cannot write output file");
  381.         return (0);
  382.     }
  383.     free(buf);
  384.     return (1);
  385. }
  386.  
  387. void
  388. unexec(
  389.        char *outfile,
  390.        char *infile
  391.        )
  392. {
  393.     int infd;
  394.     int outfd;
  395.     char tmpbuf[L_tmpnam];
  396.     char *tmpfile;
  397.  
  398.     infd = open(infile, O_RDONLY, 0);
  399.     if (infd < 0) {
  400.           fatal_unexec("cannot open input file `%s'", infile);
  401.         exit(1);
  402.     }
  403.     
  404.     tmpnam(tmpbuf);
  405.     tmpfile = rindex(tmpbuf, '/');
  406.     if (tmpfile == NULL) {
  407.         tmpfile = tmpbuf;
  408.     } else {
  409.         tmpfile++;
  410.     }
  411.     outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
  412.     if (outfd < 0) {
  413.         close(infd);
  414.         fatal_unexec("cannot open tmp file `%s'", tmpfile);
  415.         exit(1);
  416.     }
  417.     if (!unexec_doit(infd, outfd)) {
  418.         close(infd);
  419.         close(outfd);
  420.         unlink(tmpfile);
  421.         exit(1);
  422.     }
  423.     close(infd);
  424.     close(outfd);
  425.     if (rename(tmpfile, outfile) < 0) {
  426.         unlink(tmpfile);
  427.         fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
  428.         exit(1);
  429.     }
  430. }
  431.